package ge.scenes;

import ge.engine.Positionable;

import java.util.Collections;

public class MovementTrack extends Track {

	private Positionable element;
	private double incX,incY;
	private double initalX, initalY;
	private double interpolationTime, baseTime;
	private double duration;
	/**
	 * 	That track permits use position frames in order to make
	 *  interpolation movement.
	 * @param element To be moved
	 * @param scene The scene where will be played, another one can have
	 * 	unpredictable behaviors.
	 */
	public MovementTrack(Positionable element, Scene scene)
	{
		super();
		this.element = element;
		initalX = element.getX();
		initalY = element.getY();
		incY = incX = 0;
		duration = scene.getDuration();
	}
	/**
	 * 	Adds a new movement frame.
	 *  The element will be at that frame in that moment unless
	 *  you modify its position. It will always try to approach
	 *  to the next frame since its actual position, not the 
	 *  supposed last frame position.
	 *  
	 *  The position it's always relative to the inital position.
	 *  
	 * @param time Time of the frame
	 * @param x Position x should to be at that frame
	 * @param y Position Y should to be at that frame
	 */
	public void addFrame(double time, double x, double y)
	{
		clueFrames.add(new MovementFrame(time, x, y));
		//Inefficient, but.. it's the only form to go through it
		Collections.sort(clueFrames);
	}
	
	@Override
	protected void reachFrame(Frame f)
	{
		double incTime;
		
		if(actualFrame+1 < clueFrames.size())
		{
			baseTime = (actualFrame > -1?f.getTime():0);
			MovementFrame mf =  (MovementFrame) clueFrames.get(actualFrame+1);
			//Caso especial de que sea el primero
			incTime = mf.getTime()-baseTime ;
			
			//element.getX() should be f.getX(), but not there can be exception
			incX = (double) ((mf.getX()+initalX-element.getX())/incTime);
			incY = (double) ((mf.getY()+initalY-element.getY())/incTime);
		}
		else
			incX = incY = 0;
		interpolationTime = 0;
	}

	@Override
	protected void reachReverseFrame(Frame f) 
	{
		double incTime;
 
		if(actualFrame  > 0)
		{
			baseTime = (actualFrame < clueFrames.size()?f.getTime():duration);
			MovementFrame mf =  (MovementFrame) clueFrames.get(actualFrame-1);
			//Caso Especial de que sea el ultimo
			incTime = baseTime - mf.getTime();
			incX = (double) ((mf.getX()+initalX-element.getX())/incTime);
			incY = (double) ((mf.getY()+initalY-element.getY())/incTime);
		}
		else
			incX = incY = 0;
		interpolationTime = 0;
	}

	@Override
	protected void currentTimeJump(double time, boolean advance) {
		
		actualFrame = getIndexOfFrameBefore(time);
		//Si avanzo me interesa el anterior
		if(advance)
		{
			if(actualFrame > -1)
				reachFrame(clueFrames.get(actualFrame));
			else 
				incX = incY = 0;
		}
		else
		{
			//Si vamos aun no hemos llegado al Frame, estamos en el siguiente
			if(actualFrame > -1)
			{
				actualFrame++;	
				reachFrame(clueFrames.get(actualFrame-1));
			}
			else
				incX = incY = 0;
		}

	}
	/**
	 *  Makes the interpolation
	 * @param time Actual time of the scene
	 */
	private void interpolate(double time)
	{
		if(incX == 0 && incY == 0)
			return;
		//gets the real increment
		double incTime = Math.abs(time - baseTime) -  interpolationTime;
		//move element
		double newX = (double)(element.getX()+incX*incTime);
		double newY =  (double)(element.getY()+incY*incTime);
		element.setPos(newX,newY);
		//updates time
		interpolationTime+=incTime;
	}
	@Override
	protected void update(double time) 
	{
			interpolate(time);
	}


	 

	private class MovementFrame extends Frame
	{
		private double x,y;
		/**
		 * 	Creates a new Movement Frame
		 * @param time Time of the frame
		 * @param x Position X
		 * @param y Position Y
		 */
		public MovementFrame(double time, double x, double y)
		{
			super(time);
			this.x = x;
			this.y = y;
		}
		public double getX() {
			return x;
		}
		public double getY() {
			return y;
		}
		
		
	}

}
